using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace Raxxla.DayBreak.Core.Collections
{
    public class ObjectMap<T> where T: class
    {
        #region nested types
        [StructLayout(LayoutKind.Sequential)]
        public struct Enumerator
        {
            private int index;
            private readonly ObjectMap<T> list;

            public Enumerator(ObjectMap<T> list)
            {
                this.index = -1;
                this.list = list;
            }

            public bool MoveNext()
            {
                this.index++;
                return (index < this.list.length);
            }
            public void Reset()
            {
                this.index = -1;
            }

            public T Current
            {
                get
                {
                    return this.list[this.index];
                }
            }


        }
        #endregion

//        public static ObjectMap<T> Instance = new ObjectMap<T>();

        public static int Granularity = 256;
        private T[] elements;
        private int length;

        public ObjectMap()
        {
            this.length = 0;
            this.elements = new T[Granularity];

        }
        public ObjectMap(int capacity)
        {
            this.length = 0;
            this.elements = new T[capacity];
        }
        public ObjectMap(params T[] elements)
        {
            this.elements = elements;
            this.length = elements.Length;
        }

        public int Add(T element)
        {
            int _idx = this.elements.Length;
            int _count = this.length++;

            if (_count == _idx)
            {
                int _copacity = _idx * 2;

                if (_copacity < 4)
                    _copacity = 4;

                T[] _tmpArray = new T[_copacity];

                for (int i = 0; i < _idx; i++)
                {
                    _tmpArray[i] = this.elements[i];
                    this.elements[i] = null;
                }

                this.elements = null;
                this.elements = _tmpArray;
            }
            this.elements[_count] = element;

            return _count;

        }

        public ObjectMap<T> Clone()
        {
            ObjectMap<T> _result = new ObjectMap<T>(length);
            _result.length = length;

            for (int i = 0; i < length; i++)
                _result.elements[i] = elements[i];

            return _result;

        }
        public Enumerator GetEnumerator()
        {
            return new ObjectMap<T>.Enumerator(this);
        }

        void Enlarge()
        {
            T[] tmp = new T[elements.Length + Granularity];

            elements.CopyTo(tmp, 0);
            elements = tmp;
        }
        void Enlarge(int amount)
        {
            int _len =0;

            if ((elements.Length + Granularity) > amount)
                _len = elements.Length + Granularity;
            else
                _len = amount;

            T[] tmp = new T[_len];

            elements.CopyTo(tmp, 0);
            elements = tmp;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public T this[int index]
        {
            get
            {
                return this.elements[index];
            }
            set
            {
                if (elements.Length < (index + 1))
                    Enlarge(index+1);

                if (length < index)
                    length = index;

                this.elements[index] = value;
            }
        }

        public int Copacity
        {
            get { return this.elements.Length; }
        }

        public int Length
        {
            get
            {
                return this.length;
            }
        }
    }
}
